package com.skilltrack.enrol.service.impl;


import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.skilltrack.enrol.mapper.CourseCategoryMapper;
import com.skilltrack.enrol.model.dto.CourseCategoryTreeDto;
import com.skilltrack.enrol.model.po.CourseCategory;
import com.skilltrack.enrol.service.CourseCategoryService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 课程分类 服务实现类
 * </p>
 *
 * @author itcast
 */
@Slf4j
@Service
public class CourseCategoryServiceImpl extends ServiceImpl<CourseCategoryMapper, CourseCategory> implements CourseCategoryService {

    @Autowired
    private CourseCategoryMapper courseCategoryMapper;

    /**
     * 课程分类树形结构查询
     * @param id
     * @return
     */
    @Override
    public List<CourseCategoryTreeDto> queryTreeNodes(String id) {
        //调用mapper递归查询出分类信息
        List<CourseCategoryTreeDto> courseCategoryTreeDtos = courseCategoryMapper.selectTreeNodes(id);

        //找到每个节点的子节点,最终封装成List<CourseCategoryTreeDto>
        //先将list转成map,key就是节点的id,value就是CourseCategoryTreeDto对象,目的就是为了方便从map中获取结点

        /**
         *这段代码的功能是将 courseCategoryTreeDtos 列表转换为一个以节点 id 为键、节点对象为值的 Map，具体逻辑如下：
         *使用 stream() 遍历 courseCategoryTreeDtos 列表。
         *过滤掉 id 等于传入参数 id 的节点。
         *使用 Collectors.toMap() 将列表元素转换为 Map，其中键为节点的 id，值为节点对象。
         *在键冲突时保留后者 (key1, key2) -> key2。
         */
        Map<String, CourseCategoryTreeDto> mapTemp = courseCategoryTreeDtos.stream().filter(item -> !id.equals(item.getId())).collect(Collectors.toMap(key -> key.getId(), value -> value, (key1, key2) -> key2));

        //定义一个List作为最终返回的List
        List<CourseCategoryTreeDto> categoryTreeList= new ArrayList<>();

        //从头遍历List<CourseCategoryTreeDto>,一边遍历一边找子节点放在父节点的childrenTreeNodes中
        courseCategoryTreeDtos.stream().filter(item -> !id.equals(item.getId())).forEach(item -> {
            //起始处理
            //向list写入数据 这里list中没有根节点,存储的是目标节点（由参数 id 指定）的直接子节点，且仅限于最近的一层子节点。
            if (item.getParentid().equals(id)){
                categoryTreeList.add(item);
            }

            //找到节点的父节点
            CourseCategoryTreeDto courseCategoryTreeDto = mapTemp.get(item.getParentid());

            //如果父节点不为空,也就是map里面存放有这个节点
            if (courseCategoryTreeDto != null) {

                //如果该父节点的getChildrenTreeNodes属性为空，则创建一个空的List赋值给该属性,因为我们要向该属性(集合)中添加子节点
                //(因为Mapper查询出来的courseCategoryTreeDtos可能为null)
                if (courseCategoryTreeDto.getChildrenTreeNodes() == null) {
                    courseCategoryTreeDto.setChildrenTreeNodes(new ArrayList<CourseCategoryTreeDto>());
                }

                //把每一个节点的子节点放在父节点的childrenTreeNodes中
                //当前遍历的节点就是"子节点", 父节点就是前面mapTemp.get(item.getParentid())拿到的节点courseCategoryTreeDto
                //所以这段代码就是在把当前遍历的节点的 "父节点"courseCategoryTreeDto 里面的 ChildrenTreeNodes 属性添加上当前遍历的 "子节点"item
                courseCategoryTreeDto.getChildrenTreeNodes().add(item);
            }
        });

        //整个循环的过程都是在往当前节点中的childrenTreeNodes属性中添加当前节点的子节点
        //这个过程都是在Mapper查询出来的courseCategoryTreeDtos中进行的,也就是数据查询出来后,我们对里面的结构进行了重组,把他变成树形结构
        //所以返回的依旧是Mapper查询出来的数据
        return categoryTreeList;
    }
}
